﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace common.Framework.Encryption
{
	/**
	 * 
	 */
	public class EncryReach : IEncyface
	{
		#region 变量
		//DES默认密钥向量
		private static readonly byte[] DES_IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
		//AES默认密钥向量   
		public static readonly byte[] AES_IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
		//私钥
		public static string RSAprivateKey = "";
		//公钥
		public static string RSApublicKey = "";

		public EncryReach()
		{
			RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
			RSAprivateKey = RSA.ToXmlString(true);
			RSApublicKey = RSA.ToXmlString(false);
		}
		#endregion

		#region  RSA 加密

		/// <summary>
		/// RSA 加密
		/// </summary>
		/// <param name="plaintext"></param>
		/// <param name="publicKey"></param>
		/// <returns></returns>
		public string EncryptByRSA(string plaintext, string publicKey)
		{
			UnicodeEncoding ByteConverter = new UnicodeEncoding();
			byte[] dataToEncrypt = ByteConverter.GetBytes(plaintext);
			using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
			{
				RSA.FromXmlString(publicKey);
				byte[] encryptedData = RSA.Encrypt(dataToEncrypt, false);
				return Convert.ToBase64String(encryptedData);
			}
		}
		/// <summary>
		/// RSA 解密
		/// </summary>
		/// <param name="ciphertext"></param>
		/// <param name="privateKey"></param>
		/// <returns></returns>
		public string DecryptByRSA(string ciphertext, string privateKey)
		{
			UnicodeEncoding byteConverter = new UnicodeEncoding();
			using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
			{
				RSA.FromXmlString(privateKey);
				byte[] encryptedData = Convert.FromBase64String(ciphertext);
				byte[] decryptedData = RSA.Decrypt(encryptedData, false);
				return byteConverter.GetString(decryptedData);
			}
		}

		#endregion

		#region RSA 加密

		/// <summary>
		/// AES 解密
		/// </summary>
		/// <param name="input"></param>
		/// <param name="key"></param>
		/// <returns></returns>
		public string DecryptByAES(string input, string key)
		{
			//byte[] inputBytes = Convert.FromBase64String(input); //Encoding.UTF8.GetBytes(input);
			string[] sInput = input.Split("-".ToCharArray());
			byte[] inputBytes = new byte[sInput.Length];
			for (int i = 0; i < sInput.Length; i++)
			{
				inputBytes[i] = byte.Parse(sInput[i], NumberStyles.HexNumber);
			}
			byte[] keyBytes = Encoding.UTF8.GetBytes(key.Substring(0, 32));
			using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
			{
				aesAlg.Key = keyBytes;
				aesAlg.IV = AES_IV;

				ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
				using (MemoryStream msEncrypt = new MemoryStream(inputBytes))
				{
					using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, decryptor, CryptoStreamMode.Read))
					{
						using (StreamReader srEncrypt = new StreamReader(csEncrypt))
						{
							return srEncrypt.ReadToEnd();
						}
					}
				}
			}
		}
		/// <summary>
		/// AES 加密
		/// </summary>
		/// <param name="input"></param>
		/// <param name="key"></param>
		/// <returns></returns>
		public string EncryptByAES(string input, string key)
		{
			byte[] keyBytes = Encoding.UTF8.GetBytes(key.Substring(0, 32));
			using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
			{
				aesAlg.Key = keyBytes;
				aesAlg.IV = AES_IV;

				ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
				using (MemoryStream msEncrypt = new MemoryStream())
				{
					using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
					{
						using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
						{
							swEncrypt.Write(input);
						}
						byte[] bytes = msEncrypt.ToArray();
						//return Convert.ToBase64String(bytes);//此方法不可用
						return BitConverter.ToString(bytes);
					}
				}
			}
		}

		/// <summary> 
		/// AES加密        
		/// </summary> 
		/// <param name="inputdata">输入的数据</param>         
		/// <param name="iv">向量128位</param>         
		/// <param name="strKey">加密密钥</param>         
		/// <returns></returns> 
		public static byte[] EncryptByAES(byte[] inputdata, byte[] key, byte[] iv)
		{
			using (AesCryptoServiceProvider aesAlg = new AesCryptoServiceProvider())
			{
				aesAlg.Key = key;
				aesAlg.IV = iv;

				ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
				using (MemoryStream msEncrypt = new MemoryStream())
				{
					using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
					{
						using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
						{
							swEncrypt.Write(inputdata);
						}
						byte[] encrypted = msEncrypt.ToArray();
						return encrypted;
					}
				}
			}
		}
		/// <summary>         
		/// AES解密         
		/// </summary> 
		/// <param name="inputdata">输入的数据</param>                
		/// <param name="key">key</param>         
		/// <param name="iv">向量128</param> 
		/// <returns></returns> 
		public static byte[] DecryptByAES(byte[] inputBytes, byte[] key, byte[] iv)
		{
			Aes aes = new AesCryptoServiceProvider();
			aes.Key = key;
			aes.IV = iv;
			byte[] decryptBytes;
			using (MemoryStream ms = new MemoryStream(inputBytes))
			{
				using (CryptoStream cs = new CryptoStream(ms, aes.CreateDecryptor(), CryptoStreamMode.Read))
				{
					using (StreamReader reader = new StreamReader(cs))
					{
						string result = reader.ReadToEnd();
						decryptBytes = Encoding.UTF8.GetBytes(result);
					}
				}
			}

			return decryptBytes;
		}


		#endregion

		#region SHA1加密
		/// <summary>
		/// SHA1加密
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		public string EncryptBySHA1(string input)
		{
			SHA1 sha = new SHA1CryptoServiceProvider();
			byte[] bytes = Encoding.Unicode.GetBytes(input);
			byte[] result = sha.ComputeHash(bytes);
			return BitConverter.ToString(result);
		}
		#endregion

		#region 加密字符串

		/// <summary>
		///  加密字符串
		/// </summary>
		/// <param name="input"></param>
		/// <param name="sKey"></param>
		/// <returns></returns>
		public string EncryptString(string input, string sKey)
		{
			byte[] data = Encoding.UTF8.GetBytes(input);
			using (DESCryptoServiceProvider des = new DESCryptoServiceProvider())
			{
				des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
				des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
				ICryptoTransform desencrypt = des.CreateEncryptor();
				byte[] result = desencrypt.TransformFinalBlock(data, 0, data.Length);
				return BitConverter.ToString(result);
			}

		}
		/// <summary>
		/// 解密字符串
		/// </summary>
		/// <param name="input"></param>
		/// <param name="sKey"></param>
		/// <returns></returns>
		public string DecryptString(string input, string sKey)
		{
			string[] sInput = input.Split("-".ToCharArray());
			byte[] data = new byte[sInput.Length];
			for (int i = 0; i < sInput.Length; i++)
			{
				data[i] = byte.Parse(sInput[i], NumberStyles.HexNumber);
			}
			using (DESCryptoServiceProvider des = new DESCryptoServiceProvider())
			{
				des.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
				des.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
				ICryptoTransform desencrypt = des.CreateDecryptor();
				byte[] result = desencrypt.TransformFinalBlock(data, 0, data.Length);
				return Encoding.UTF8.GetString(result);
			}
		}
		#endregion

		#region  MD5
		/// <summary>
		/// MD5 加密 16进制字符串
		/// </summary>
		/// <param name="input">字符串</param>
		/// <returns>加密后的字符串</returns>
		public string EncrypyByMD5(string input)
		{
			MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
			//转换为字节数组
			//计算字节数组的哈希值
			byte[] encryptedBytes = md5.ComputeHash(Encoding.ASCII.GetBytes(input));
			StringBuilder sb = new StringBuilder();
			for (int i = 0; i < encryptedBytes.Length; i++)
			{
				sb.AppendFormat("{0:x2}", encryptedBytes[i]);
			}
			return sb.ToString();
		}
		/// <summary>
		/// md5加密
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		public string EncryMD5(string input)
		{
			MD5 md5Hasher = MD5.Create();
			byte[] data = md5Hasher.ComputeHash(Encoding.UTF8.GetBytes(input));

			StringBuilder sBuilder = new StringBuilder();
			//将每个字节转为16进制
			for (int i = 0; i < data.Length; i++)
			{
				sBuilder.Append(data[i].ToString("x2"));
			}

			return sBuilder.ToString();
		}
		#endregion

		#region DES 
		/// <summary>
		/// 加密
		/// </summary>
		/// <param name="input"></param>
		/// <param name="key"></param>
		/// <returns></returns>
		public string EncryptByDES(string input, string key)
		{
			byte[] inputBytes = Encoding.UTF8.GetBytes(input); //Encoding.UTF8.GetBytes(input);
			byte[] keyBytes = ASCIIEncoding.UTF8.GetBytes(key);
			byte[] encryptBytes = EncryptByDES(inputBytes, keyBytes, keyBytes);
			//string result = Encoding.UTF8.GetString(encryptBytes); //无法解码,其加密结果中文出现乱码：d\"�e����(��uπ�W��-��,_�\nJn7 
			//原因：如果明文为中文，UTF8编码两个字节标识一个中文字符，但是加密后，两个字节密文，不一定还是中文字符。
			using (DES des = new DESCryptoServiceProvider())
			{
				using (MemoryStream ms = new MemoryStream())
				{
					using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
					{
						using (StreamWriter writer = new StreamWriter(cs))
						{
							writer.Write(inputBytes);
						}
					}
				}
			}

			string result = Convert.ToBase64String(encryptBytes);

			return result;
		}

		/// <summary>
		/// 解密
		/// </summary>
		/// <param name="input"></param>
		/// <param name="key"></param>
		/// <returns></returns>
		public string DecryptByDES(string input, string key)
		{
			//UTF8无法解密，Error: 要解密的数据的长度无效。
			//byte[] inputBytes = Encoding.UTF8.GetBytes(input);//UTF8乱码，见加密算法
			byte[] inputBytes = Convert.FromBase64String(input);

			byte[] keyBytes = ASCIIEncoding.UTF8.GetBytes(key);
			byte[] resultBytes = DecryptByDES(inputBytes, keyBytes, keyBytes);

			string result = Encoding.UTF8.GetString(resultBytes);

			return result;
		}
		/// <summary>
		/// 加密
		/// </summary>
		/// <param name="inputBytes"></param>
		/// <param name="key"></param>
		/// <param name="IV"></param>
		/// <returns></returns>
		public byte[] EncryptByDES(byte[] inputBytes, byte[] key, byte[] IV)
		{
			DES des = new DESCryptoServiceProvider();
			//建立加密对象的密钥和偏移量
			des.Key = key;
			des.IV = IV;
			string result = string.Empty;

			//1、如果通过CryptoStreamMode.Write方式进行加密，然后CryptoStreamMode.Read方式进行解密，解密成功。
			using (MemoryStream ms = new MemoryStream())
			{
				using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
				{
					cs.Write(inputBytes, 0, inputBytes.Length);
				}
				return ms.ToArray();
			}
			//2、如果通过CryptoStreamMode.Write方式进行加密，然后再用CryptoStreamMode.Write方式进行解密，可以得到正确结果
			//3、如果通过CryptoStreamMode.Read方式进行加密，然后再用CryptoStreamMode.Read方式进行解密，无法解密，Error：要解密的数据的长度无效。
			//4、如果通过CryptoStreamMode.Read方式进行加密，然后再用CryptoStreamMode.Write方式进行解密,无法解密，Error：要解密的数据的长度无效。
			//using (MemoryStream ms = new MemoryStream(inputBytes))
			//{
			//    using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Read))
			//    {
			//        using (StreamReader reader = new StreamReader(cs))
			//        {
			//            result = reader.ReadToEnd();
			//            return Encoding.UTF8.GetBytes(result);
			//        }
			//    }
			//}
		}
		/// <summary>
		/// 解密
		/// </summary>
		/// <param name="inputBytes"></param>
		/// <param name="key"></param>
		/// <param name="iv"></param>
		/// <returns></returns>
		public byte[] DecryptByDES(byte[] inputBytes, byte[] key, byte[] iv)
		{
			DESCryptoServiceProvider des = new DESCryptoServiceProvider();
			//建立加密对象的密钥和偏移量，此值重要，不能修改
			des.Key = key;
			des.IV = iv;

			//通过write方式解密
			//using (MemoryStream ms = new MemoryStream())
			//{
			//    using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write))
			//    {
			//        cs.Write(inputBytes, 0, inputBytes.Length);
			//    }
			//    return ms.ToArray();
			//}

			//通过read方式解密
			using (MemoryStream ms = new MemoryStream(inputBytes))
			{
				using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Read))
				{
					using (StreamReader reader = new StreamReader(cs))
					{
						string result = reader.ReadToEnd();
						return Encoding.UTF8.GetBytes(result);
					}
				}
			}

			//错误写法,注意哪个是输出流的位置，如果范围ms，与原文不一致。
			//using (MemoryStream ms = new MemoryStream(inputBytes))
			//{
			//    using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Read))
			//    {
			//        cs.Read(inputBytes, 0, inputBytes.Length);
			//    }
			//    return ms.ToArray();
			//}
		}
		#endregion

		#region 获取RSA加密 KEY
		/// <summary>
		/// 获取RSA KEY
		/// 键为公钥，值为私钥
		/// </summary>
		/// <returns></returns>
		public static KeyValuePair<string, string> CreateRSAKey()
		{
			RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
			string privateKey = RSA.ToXmlString(true);
			string publicKey = RSA.ToXmlString(false);
			return new KeyValuePair<string, string>(publicKey, privateKey);
		}
		#endregion

		#region 数字签名  验证数字签名
		/// <summary>
		/// 数字签名
		/// </summary>
		/// <param name="plaintext">原文</param>
		/// <param name="privateKey">私钥</param>
		/// <returns>签名</returns>
		public static string HashAndSignString(string plaintext, string privateKey)
		{
			UnicodeEncoding ByteConverter = new UnicodeEncoding();
			byte[] dataToEncrypt = ByteConverter.GetBytes(plaintext);

			using (RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider())
			{
				RSAalg.FromXmlString(privateKey);
				//使用SHA1进行摘要算法，生成签名
				byte[] encryptedData = RSAalg.SignData(dataToEncrypt, new SHA1CryptoServiceProvider());
				return Convert.ToBase64String(encryptedData);
			}
		}
		/// <summary>
		/// 验证签名
		/// </summary>
		/// <param name="plaintext">原文</param>
		/// <param name="SignedData">签名</param>
		/// <param name="publicKey">公钥</param>
		/// <returns></returns>
		public static bool VerifySigned(string plaintext, string SignedData, string publicKey)
		{
			using (RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider())
			{
				RSAalg.FromXmlString(publicKey);
				UnicodeEncoding ByteConverter = new UnicodeEncoding();
				byte[] dataToVerifyBytes = ByteConverter.GetBytes(plaintext);
				byte[] signedDataBytes = Convert.FromBase64String(SignedData);
				return RSAalg.VerifyData(dataToVerifyBytes, new SHA1CryptoServiceProvider(), signedDataBytes);
			}
		}
		#endregion

	}
}
